package com.os.core.service.extend.impl;

import cn.smallbun.screw.core.Configuration;
import cn.smallbun.screw.core.engine.EngineConfig;
import cn.smallbun.screw.core.engine.EngineFileType;
import cn.smallbun.screw.core.engine.EngineTemplateType;
import cn.smallbun.screw.core.execute.DocumentationExecute;
import cn.smallbun.screw.core.process.ProcessConfig;
import com.os.common.entity.extend.DocumentInfo;
import com.os.common.utils.FileUtil;
import com.os.common.utils.MyUtil;
import com.os.core.service.extend.DocumentService;
import com.os.system.service.DataSourceService;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 描述：文档服务实现类
 *
 * @author huxuehao
 **/
@Service
public class DocumentServiceImpl implements DocumentService {
    private static final String FILE_OUTPUT_DIR = "os_doc_dir";

    private final DataSourceService dataSourceService;

    public DocumentServiceImpl(DataSourceService dataSourceService) {
        this.dataSourceService = dataSourceService;
    }

    @Override
    public void genWord(DocumentInfo documentInfo, HttpServletResponse response) throws SQLException {
        String fileName = genDocument(documentInfo, EngineFileType.WORD);
        downFile(fileName, response);
    }

    @Override
    public void genHtml(DocumentInfo documentInfo, HttpServletResponse response) throws SQLException {
        String fileName = genDocument(documentInfo, EngineFileType.HTML);
        downFile(fileName, response);
    }

    @Override
    public void genMD(DocumentInfo documentInfo, HttpServletResponse response) throws SQLException {
        String fileName = genDocument(documentInfo, EngineFileType.MD);
        downFile(fileName, response);
    }

    private String genDocument(DocumentInfo documentInfo, EngineFileType type) throws SQLException {
        // 获取数据源信息
        com.os.common.entity.datasource.DataSource targetDataSource = dataSourceService.selectById(documentInfo.getDatasourceId());
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setDriverClassName(targetDataSource.getDrive());
        hikariConfig.setJdbcUrl(targetDataSource.getUrl());
        hikariConfig.setUsername(targetDataSource.getUserName());
        hikariConfig.setPassword(targetDataSource.getPassword());

        //设置可以获取tables remarks信息
        hikariConfig.addDataSourceProperty("useInformationSchema", "true");
        hikariConfig.setMinimumIdle(2);
        hikariConfig.setMaximumPoolSize(5);
        DataSource dataSource = new HikariDataSource(hikariConfig);
        String fileName = documentInfo.getFileName().concat("_").concat(MyUtil.nextId());
        EngineConfig engineConfig  = EngineConfig.builder()
                .fileOutputDir(FILE_OUTPUT_DIR)
                .openOutputDir(false)
                .fileType(type)
                .produceType(EngineTemplateType.freemarker)
                .fileName(fileName)
                .build();

        Configuration config = Configuration.builder()
                .version(documentInfo.getVersion())
                .description(documentInfo.getDescription())
                .dataSource(dataSource)
                .engineConfig(engineConfig)
                .produceConfig(getProcessConfig(documentInfo))
                .build();
        new DocumentationExecute(config).execute();
        return fileName.concat(type.getFileSuffix());
    }

    private ProcessConfig getProcessConfig(DocumentInfo documentInfo) {
        List<String> ignoreTableName = documentInfo.getIgnoreTableName()==null? Collections.emptyList() :documentInfo.getIgnoreTableName();
        List<String> ignorePrefix = documentInfo.getIgnorePrefix()==null? Collections.emptyList() :documentInfo.getIgnorePrefix();
        List<String> ignoreSuffix = documentInfo.getIgnoreSuffix()==null? Collections.emptyList() :documentInfo.getIgnoreSuffix();
        return ProcessConfig.builder()
                .designatedTableName(new ArrayList<>())
                .designatedTablePrefix(new ArrayList<>())
                .designatedTableSuffix(new ArrayList<>())
                .ignoreTableName(ignoreTableName)
                .ignoreTablePrefix(ignorePrefix)
                .ignoreTableSuffix(ignoreSuffix)
                .build();
    }

    private void downFile(String fileName, HttpServletResponse response) {
        String pathName = FILE_OUTPUT_DIR + "\\" + fileName;
        File file = new File(pathName);
        byte[] buffer = new byte[1024];
        BufferedInputStream bis = null;
        OutputStream os = null;
        try {
            if (file.exists()) {
                FileUtil.setDownloadHeader(response);
                os = response.getOutputStream();
                bis = new BufferedInputStream(Files.newInputStream(file.toPath()));
                int len = bis.read(buffer);
                while(len != -1){
                    os.write(buffer,0,len);
                    len = bis.read(buffer);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(bis != null) {
                    bis.close();
                }
                if(os != null) {
                    os.flush();
                    os.close();
                }
                Files.delete(Paths.get(pathName));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
